package com.fastloan.mgt.processcontrol.service;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fastloan.mgt.application.base.enums.ApplicationStatusEnum;
import com.fastloan.mgt.application.base.model.Application;
import com.fastloan.mgt.application.base.model.ProcessFlow;
import com.fastloan.mgt.application.base.service.ApplicationService;
import com.fastloan.mgt.application.base.util.ApplicationUtil;
import com.fastloan.mgt.application.contract.service.ChoiceContractService;
import com.fastloan.mgt.processcontrol.base.model.Process;
import com.fastloan.mgt.processcontrol.base.model.ProcessBaseSession;
import com.fastloan.mgt.processcontrol.base.model.CustomProcess;
import com.fastloan.mgt.processcontrol.base.model.ProcessSchedule;
import com.fastloan.mgt.processcontrol.base.service.ProcessDispatcher;
import com.fastloan.mgt.processcontrol.base.service.SubjectProcessService;
import com.fastloan.mgt.processcontrol.dao.ProcessFlowMapper;
import com.fastloan.mgt.processcontrol.dao.ProcessMapper;
import com.fastloan.mgt.processcontrol.dao.ProcessScheduleMapper;
import com.fastloan.mgt.processcontrol.dao.ProcessSessionMapper;
import com.fastloan.mgt.processcontrol.model.ProcessPo;
import com.fastloan.mgt.processcontrol.model.ProcessSchedulePo;
import com.fastloan.mgt.processcontrol.model.ProcessSessionPo;
import com.fastloan.utils.DozerUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.io.IOException;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author yanwe
 * createTime 2017-11-2017/11/6 18:49
 */
@Service
public class SubjectProcessServiceImpl implements SubjectProcessService {

    @Autowired
    private ProcessScheduleMapper processScheduleMapper;

    @Autowired
    private ProcessSessionMapper processSessionMapper;

    @Autowired
    private ProcessMapper processSubjectMapper;

    @Autowired
    private ProcessFlowMapper processFlowMapper;

    @Autowired
    private ApplicationService applicationService;

    @Autowired
    private ChoiceContractService choiceContractService;

    @Override
    public List<CustomProcess> selectProcessFlow(String processId) {
        return processFlowMapper.selectProcessFlow(processId)
                .stream().map(productFlow -> CustomProcess.CustomProcessBuilder.aCustomProcess()
                .withProcessClass(productFlow.getProcessClass())
                .withProcessOrder(productFlow.getOrderBy()).build())
                .collect(Collectors.toList());
    }

    @Override
    public String createProcess(Process process, Function<String,List<ProcessFlow>> function) {
        ProcessPo processSubjectPo = DozerUtil.map(process, ProcessPo.class);
        processSubjectMapper.insert(processSubjectPo);
        List<ProcessFlow> processFlows = function.apply(processSubjectPo.getProcessId());
        processFlows.forEach(processFlowMapper::insert);
        return processSubjectPo.getProcessId();
    }

    @Override
    public Process getProcess(String processId) {
        return DozerUtil.map(processSubjectMapper.selectByPrimaryKey(processId),Process.class);
    }

    @Override
    public List<String> getNeedCleanSubjects(List<Integer> status) {
        Example example = new Example(Application.class);
        example.createCriteria().andIn("applicationStatus",status);
        return applicationService.selectByExample(example).stream()
                .map(Application::getProcessId).collect(Collectors.toList());
    }

    @Override
    @Transactional
    public void saveProcessSession(ProcessBaseSession processSession) {
        processSessionMapper.deleteByPrimaryKey(processSession.getProcessId());
        ProcessSessionPo processSessionPo = new ProcessSessionPo();
        processSessionPo.setProcessId(processSession.getProcessId());
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            processSessionPo.setSession(objectMapper.writeValueAsString(processSession));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        processSessionMapper.insert(processSessionPo);
    }

    @Override
    public ProcessBaseSession getProcessSession(String processId) {
        ProcessSessionPo processSessionPo = processSessionMapper.selectByPrimaryKey(processId);
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            return objectMapper.readValue(processSessionPo.getSession(),ProcessBaseSession.class);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    @Transactional
    public void saveProcessSchedule(String processId ,List<ProcessSchedule> processScheduleList) {
        processScheduleMapper.deleteByPrimaryKey(processId);
        ProcessSchedulePo processSchedulePo = new ProcessSchedulePo();
        processSchedulePo.setProcessId(processId);
        processSchedulePo.setSchedule(JSON.toJSONString(processScheduleList));
        processScheduleMapper.insert(processSchedulePo);
    }

    @Override
    public List<ProcessSchedule> getProcessScheduleList(String processId) {
        ProcessSchedulePo processSchedulePo = processScheduleMapper.selectByPrimaryKey(processId);
        return JSON.parseArray(processSchedulePo.getSchedule(),ProcessSchedule.class);
    }

    @Override
    public void processEndHandle(String processId) {
        String applicationId = ProcessDispatcher.getProcessSession(processId)
                .getAttribute("applicationId", String.class);
        if (applicationId != null){
            choiceContractService.choiceContract(applicationId);
        }
    }
}
